<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>烟花特效</title>
        <style>
            html,
            body {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }

            #canvas {
                display: block;
                margin: auto;
                width: 100%;
                height: 100%;
                background-image: url('./star.jpg');
            }
        </style>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script type="module">
        import {Create} from '../dist/main.js';
        const el = document.getElementById('canvas');
        const width = document.body.clientWidth;
        const height = document.body.clientHeight;
        el.width = width;
        el.height = height;
        const canvas = new Create('canvas');
        canvas.setCanvasBackground('#000');
        const ctx = canvas.ctx;
        let fireworks = [];
        let fireworkTimer = 0;

        function getHue() {
            let hue = Math.random() * 360;
            let hueVariance = 200;
            return Math.floor(Math.random() * (hue + hueVariance - (hue - hueVariance))) + (hue - hueVariance);
        }

        // 获取范围内的随机数
        function randomRange(min, max) {
            return Math.random() * (max - min) + min;
        }

        // 绘制烟花
        class Particle {
            // 初始化时的x,y坐标
            constructor(x, y, hue) {
                this.x = x;
                this.y = y;

                // 粒子坐标集合
                this.coords = [
                    [x, y],
                    [x, y],
                    [x, y]
                ];

                // 随机弧度
                this.angle = randomRange(0, Math.PI * 2);
                // 随机基本速度
                this.speed = randomRange(1, 10);

                // 摩擦系数、重力（减缓粒子速度、模拟抛物线下坠）
                this.friction = 0.95; // 百分比 不同材质的物体摩擦系数不同（有现成值）
                this.gravity = 1; // 作用于y轴加速度 模拟往下坠

                // 随机色调（基础色调-20和+20之间）
                this.hue = randomRange(hue - 20, hue + 20);
                // 随机亮度
                this.brightness = Math.floor(Math.random() * 21) + 50;
                // 初始透明度
                this.alpha = 1;
                // 随机的透明度衰变系数（透明度减淡）
                this.alphaDecay = randomRange(0.015, 0.03);
            }

            // 更新某个（索引）粒子属性
            update(index) {
                // 删掉最后一项 在最前面塞入一项
                this.coords.pop();
                this.coords.unshift([this.x, this.y]);
                this.speed *= this.friction; // 先减速

                // 由弧度计算出当前x,y坐标值
                // 难点：看原理/正弦余弦理解.png
                this.x += Math.cos(this.angle) * this.speed;
                this.y += Math.sin(this.angle) * this.speed + this.gravity;

                // 透明度衰减
                this.alpha -= this.alphaDecay;
                // 当透明度小于最小衰减值 就把这个例子对象删除
                if (this.alpha < this.alphaDecay) {
                    fireworks.splice(index, 1);
                }
            }

            // 绘制粒子（例子以line的方式）
            draw() {
                ctx.beginPath();
                // 从集合中最后一个项开始
                const [startX, startY] = this.coords[this.coords.length - 1];
                ctx.moveTo(startX, startY);
                ctx.lineTo(this.x, this.y);
                // hsla的颜色模式
                ctx.strokeStyle = `hsla(${this.hue}, 100%, ${this.brightness}%, ${this.alpha}`;
                ctx.lineWidth = 2;
                ctx.lineCap = 'round';
                ctx.stroke();
            }
        }

        function drawAnimation() {
            // 每次设置黑色背景颜色
            // canvas.setCanvasBackground('#000');

            // 设置拖尾效果
            ctx.globalCompositeOperation = 'destination-out';
            ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
            ctx.fillRect(0, 0, width, height);
            ctx.globalCompositeOperation = 'lighter';

            for (let i = 0; i < fireworks.length; i++) {
                fireworks[i].draw();
                fireworks[i].update(i);
            }

            // 定时器结束了，也没有必要再渲染了
            if (fireworkTimer === 0) {
                return;
            }
            requestAnimationFrame(drawAnimation);
        }

        // 模拟烟花位置
        function mockFireworks() {
            fireworkTimer = setInterval(() => {
                const x = Math.ceil(Math.random() * width);
                const y = Math.ceil(Math.random() * height);
                const color = getHue();
                for (let i = 0; i < 100; i++) {
                    fireworks.push(new Particle(x, y, color));
                }
            }, 300);
        }
        mockFireworks();

        drawAnimation();

        // 处理定时器的问题
        function handleVisibilityChange() {
            // tab 隐藏
            if (document.hidden) {
                clearInterval(fireworkTimer);
                fireworkTimer = 0;
            } else {
                mockFireworks();
            }
        }

        document.addEventListener('visibilitychange', handleVisibilityChange);
    </script>
</html>
